#!/usr/bin/env python3
"""
TTSMaker网站爬虫 - 使用Playwright实现
功能：打开TTSMaker网站，等待用户登录，然后进行页面分析
"""

import asyncio
import time
import csv
import os
from playwright.async_api import async_playwright, Page, Browser


class TTSMakerCrawler:
    def __init__(self, headless: bool = False):
        """
        初始化TTSMaker爬虫
        
        Args:
            headless (bool): 是否无头模式运行，默认False以便用户可以看到页面进行登录
        """
        self.headless = headless
        self.page: Page = None
        self.browser: Browser = None
        self.playwright = None
        self.url = "https://ttsmaker.cn/"
        
    async def setup_browser(self):
        """设置浏览器"""
        self.playwright = await async_playwright().start()
        
        # 针对 conda 环境和 macOS 优化的浏览器启动参数
        # 使用更保守的设置避免崩溃
        browser_args = [
            '--no-sandbox',
            '--disable-setuid-sandbox',
            '--disable-dev-shm-usage',
            '--disable-gpu',
            '--disable-software-rasterizer',
            '--disable-background-timer-throttling',
            '--disable-backgrounding-occluded-windows',
            '--disable-renderer-backgrounding',
            '--disable-features=TranslateUI,VizDisplayCompositor',
            '--disable-web-security',
            '--disable-extensions',
            '--no-first-run',
            '--no-default-browser-check',
            '--disable-default-apps',
            '--single-process'  # 使用单进程模式增加稳定性
        ]
        
        # 尝试多种浏览器和配置，解决 macOS conda 环境兼容性问题
        browser_strategies = [
            {
                "name": "Firefox (推荐)",
                "browser_type": "firefox",
                "args": []
            },
            {
                "name": "Chromium 无沙盒模式",
                "browser_type": "chromium", 
                "args": ['--no-sandbox', '--disable-web-security']
            },
            {
                "name": "Chromium 最小模式",
                "browser_type": "chromium",
                "args": ['--no-sandbox']
            },
            {
                "name": "WebKit (Safari内核)",
                "browser_type": "webkit",
                "args": []
            }
        ]
        
        for strategy in browser_strategies:
            try:
                print(f"尝试使用 {strategy['name']} 启动浏览器...")
                
                if strategy['browser_type'] == 'firefox':
                    self.browser = await self.playwright.firefox.launch(
                        headless=self.headless,
                        timeout=60000
                    )
                elif strategy['browser_type'] == 'webkit':
                    self.browser = await self.playwright.webkit.launch(
                        headless=self.headless,
                        timeout=60000
                    )
                else:  # chromium
                    self.browser = await self.playwright.chromium.launch(
                        headless=self.headless,
                        args=strategy['args'],
                        timeout=60000
                    )
                
                print(f"✓ {strategy['name']} 启动成功")
                break
                
            except Exception as e:
                print(f"❌ {strategy['name']} 启动失败: {str(e)}")
                if self.browser:
                    try:
                        await self.browser.close()
                    except:
                        pass
                    self.browser = None
                continue
        
        if not self.browser:
            raise Exception("所有浏览器都启动失败，请检查 Playwright 安装：playwright install")
        
        # 创建新的页面上下文 - 使用更保守的设置
        try:
            context = await self.browser.new_context(
                viewport={'width': 1280, 'height': 720},
                user_agent='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36',
                ignore_https_errors=True  # 忽略 HTTPS 错误
            )
            print("✓ 浏览器上下文创建成功")
            
            self.page = await context.new_page()
            print("✓ 页面创建成功")
            
        except Exception as e:
            print(f"❌ 页面创建失败: {str(e)}")
            if self.browser:
                await self.browser.close()
            raise e
        
    async def open_website(self):
        """打开TTSMaker网站"""
        print(f"正在打开网站: {self.url}")
        
        try:
            # 导航到网站 - 使用更保守的等待策略
            await self.page.goto(self.url, wait_until='load', timeout=45000)
            print("网站基本加载完成")
            
            # 等待页面关键元素加载
            await self.page.wait_for_selector('body', timeout=15000)
            
            # 给页面一些时间完全加载
            await asyncio.sleep(2)
            
            # 获取页面标题
            title = await self.page.title()
            print(f"页面标题: {title}")
            
            return True
            
        except Exception as e:
            print(f"打开网站失败: {str(e)}")
            return False
    
    async def analyze_page_structure(self):
        """分析页面结构"""
        print("\n=== 开始分析页面结构 ===")
        
        try:
            # 获取页面基本信息
            url = self.page.url
            title = await self.page.title()
            
            print(f"当前URL: {url}")
            print(f"页面标题: {title}")
            
            # 检查登录相关元素
            login_selectors = [
                'a[href*="login"]',
                'button:has-text("登录")',
                '.login',
                '#login',
                'a:has-text("登录")',
                'a:has-text("注册")'
            ]
            
            print("\n--- 登录相关元素检查 ---")
            for selector in login_selectors:
                try:
                    element = await self.page.query_selector(selector)
                    if element:
                        text = await element.inner_text()
                        print(f"找到登录元素: {selector} -> 文本: '{text}'")
                except:
                    continue
            
            # 检查主要功能区域
            main_selectors = [
                'textarea',
                'input[type="text"]',
                '.text-input',
                'select',
                'button:has-text("转换")',
                'button:has-text("合成")',
                '.voice-select',
                '.language-select'
            ]
            
            print("\n--- 主要功能元素检查 ---")
            for selector in main_selectors:
                try:
                    elements = await self.page.query_selector_all(selector)
                    if elements:
                        print(f"找到 {len(elements)} 个元素: {selector}")
                        # 获取第一个元素的一些信息
                        if elements:
                            first_element = elements[0]
                            try:
                                tag_name = await first_element.evaluate('el => el.tagName')
                                class_name = await first_element.get_attribute('class') or 'N/A'
                                placeholder = await first_element.get_attribute('placeholder') or 'N/A'
                                print(f"  - 标签: {tag_name}, 类名: {class_name}, 占位符: {placeholder}")
                            except:
                                pass
                except:
                    continue
            
            # 检查是否已登录
            await self.check_login_status()
            
        except Exception as e:
            print(f"页面分析失败: {str(e)}")
    
    async def check_login_status(self):
        """检查登录状态"""
        print("\n--- 登录状态检查 ---")
        
        # 检查可能表示已登录的元素
        logged_in_indicators = [
            'a:has-text("退出")',
            'a:has-text("登出")',
            '.user-info',
            '.username',
            'button:has-text("退出")',
            '.logout'
        ]
        
        is_logged_in = False
        for selector in logged_in_indicators:
            try:
                element = await self.page.query_selector(selector)
                if element:
                    text = await element.inner_text()
                    print(f"检测到登录状态指示器: {selector} -> '{text}'")
                    is_logged_in = True
                    break
            except:
                continue
        
        if not is_logged_in:
            print("未检测到登录状态，用户可能需要登录")
        else:
            print("检测到用户已登录")
        
        return is_logged_in
    
    def read_csv_file(self, csv_file_path: str):
        """读取 CSV 文件内容并去重"""
        texts = []
        try:
            if not os.path.exists(csv_file_path):
                print(f"❌ CSV 文件不存在: {csv_file_path}")
                return texts
            
            with open(csv_file_path, 'r', encoding='utf-8') as file:
                # 检查文件是否为 CSV 格式（有逗号）还是简单的文本文件
                content = file.read()
                file.seek(0)
                
                if ',' in content:
                    # CSV 格式
                    csv_reader = csv.reader(file)
                    for row in csv_reader:
                        if row:  # 跳过空行
                            texts.append(row[0])  # 取第一列
                else:
                    # 简单文本文件，每行一个文本
                    for line in file:
                        line = line.strip()
                        if line:  # 跳过空行
                            texts.append(line)
            
            # 去重，保持原有顺序
            original_count = len(texts)
            unique_texts = []
            seen = set()
            for text in texts:
                if text not in seen:
                    unique_texts.append(text)
                    seen.add(text)
            
            texts = unique_texts
            removed_count = original_count - len(texts)
            
            print(f"✓ 读取完成: 原始 {original_count} 行，去重后 {len(texts)} 行")
            if removed_count > 0:
                print(f"  去除重复项: {removed_count} 个")
            
            for i, text in enumerate(texts, 1):
                print(f"  {i}. {text}")
            
        except Exception as e:
            print(f"❌ 读取 CSV 文件失败: {str(e)}")
        
        return texts
    
    async def find_text_input(self):
        """查找页面上的文本输入框"""
        print("正在查找文本输入框...")
        
        # 可能的文本输入框选择器
        input_selectors = [
            'textarea',  # 最常见的多行文本输入
            'input[type="text"]',
            'input[placeholder*="输入"]',
            'textarea[placeholder*="输入"]',
            '.text-input',
            '#text-input',
            '[contenteditable="true"]',  # 可编辑的 div
        ]
        
        for selector in input_selectors:
            try:
                elements = await self.page.query_selector_all(selector)
                print(f"查找选择器 {selector}: 找到 {len(elements)} 个元素")
                
                for i, element in enumerate(elements):
                    try:
                        # 检查元素是否可见
                        is_visible = await element.is_visible()
                        is_enabled = await element.is_enabled()
                        
                        print(f"  元素 {i+1}: 可见={is_visible}, 可用={is_enabled}")
                        
                        if is_visible and is_enabled:
                            print(f"✓ 找到可用的文本输入框: {selector} (第{i+1}个)")
                            return element
                    except Exception as e:
                        print(f"  元素 {i+1} 检查失败: {str(e)}")
                        continue
                        
            except Exception as e:
                print(f"查找选择器 {selector} 失败: {str(e)}")
                continue
        
        print("❌ 未找到合适的文本输入框")
        
        # 如果找不到，尝试截图看看页面状态
        try:
            await self.page.screenshot(path="debug_page.png")
            print("已保存调试截图: debug_page.png")
        except:
            pass
            
        return None
    
    async def input_text_to_page(self, text: str):
        """将文本输入到页面输入框"""
        try:
            # 查找输入框
            input_element = await self.find_text_input()
            if not input_element:
                return False
            
            # 点击输入框获得焦点
            await input_element.click()
            await asyncio.sleep(0.3)
            
            # 清空输入框 - 使用正确的方法
            await input_element.fill("")  # 使用 fill 方法清空
            await asyncio.sleep(0.3)
            
            # 输入文本
            await input_element.type(text, delay=50)  # 每个字符间隔50ms
            
            print(f"✓ 成功输入文本: {text}")
            return True
            
        except Exception as e:
            print(f"❌ 输入文本失败: {str(e)}")
            return False
    
    async def wait_for_conversion_complete(self, timeout: int = 120):
        """等待转换完成"""
        print("等待转换完成...")
        start_time = time.time()
        
        while time.time() - start_time < timeout:
            try:
                # 查找转换完成的指示器
                success_indicators = [
                    'text="文本转换语音文件成功"',
                    'text="转换成功"',
                    'text="转换完成"',
                    'text="生成完成"',
                    'button:has-text("下载文件到本地")',
                    'a[href*="download"]',  # 下载链接
                    'button:has-text("下载")',
                    '.download-btn',
                    '#download'
                ]
                
                for indicator in success_indicators:
                    element = await self.page.query_selector(indicator)
                    if element and await element.is_visible():
                        print("✓ 检测到转换完成，找到下载按钮")
                        return True
                
                # 检查是否有错误提示
                error_indicators = [
                    'text="转换失败"',
                    'text="错误"',
                    '.error',
                    '.alert-error'
                ]
                
                for indicator in error_indicators:
                    element = await self.page.query_selector(indicator)
                    if element and await element.is_visible():
                        error_text = await element.inner_text()
                        print(f"❌ 转换出现错误: {error_text}")
                        return False
                
                await asyncio.sleep(2)  # 每2秒检查一次
                print(f"等待转换中... ({int(time.time() - start_time)}s)")
                
            except Exception as e:
                print(f"检查转换状态时出错: {str(e)}")
                await asyncio.sleep(2)
        
        print("⚠ 转换等待超时")
        return False
    
    async def select_voice(self, voice_name: str = "Fy-樊雨-经典男声"):
        """选择指定的语音"""
        print(f"正在选择语音: {voice_name}")
        
        try:
            # 从图片可以看到，这是一个编号的语音列表，樊雨是第3个
            print("分析语音选择区域...")
            
            # 方法1: 尝试查找包含樊雨的所有文本元素
            print("方法1: 搜索包含樊雨的文本...")
            try:
                # 使用更精确的查找方式
                elements_with_fanyu = await self.page.query_selector_all('*:has-text("樊雨")')
                print(f"找到包含'樊雨'的元素: {len(elements_with_fanyu)} 个")
                
                for i, element in enumerate(elements_with_fanyu):
                    try:
                        if await element.is_visible():
                            text = await element.inner_text()
                            print(f"  元素 {i+1}: {text[:100]}...")
                            
                            if "Fy-樊雨" in text or ("樊雨" in text and "经典男声" in text):
                                print(f"✓ 找到目标语音: {text}")
                                
                                # 尝试点击这个元素
                                await element.click()
                                print("✓ 成功点击语音选项")
                                await asyncio.sleep(1)
                                return True
                    except Exception as e:
                        print(f"  处理元素失败: {e}")
                        continue
            except Exception as e:
                print(f"方法1失败: {e}")
            
            # 方法2: 查找编号为3的语音选项
            print("方法2: 查找第3个语音选项...")
            try:
                # 查找可能的语音选项容器
                voice_containers = await self.page.query_selector_all('div, li, .voice-item, .speaker-item, [class*="voice"], [class*="speaker"]')
                print(f"找到可能的语音容器: {len(voice_containers)} 个")
                
                fanyu_containers = []
                for container in voice_containers:
                    try:
                        if await container.is_visible():
                            text = await container.inner_text()
                            if "樊雨" in text and len(text) < 200:  # 限制文本长度避免获取整个页面
                                fanyu_containers.append(container)
                                print(f"  找到樊雨容器: {text[:100]}")
                    except:
                        continue
                
                # 点击第一个找到的樊雨容器
                if fanyu_containers:
                    await fanyu_containers[0].click()
                    print("✓ 成功点击樊雨语音容器")
                    await asyncio.sleep(1)
                    return True
                    
            except Exception as e:
                print(f"方法2失败: {e}")
            
            # 方法3: 尝试查找单选按钮和语音标签的组合
            print("方法3: 查找单选按钮...")
            try:
                # 查找所有单选按钮
                radio_buttons = await self.page.query_selector_all('input[type="radio"], .radio')
                print(f"找到单选按钮: {len(radio_buttons)} 个")
                
                for i, radio in enumerate(radio_buttons):
                    try:
                        if await radio.is_visible():
                            # 查找这个单选按钮附近的文本
                            parent = radio
                            for _ in range(3):  # 向上查找3层父元素
                                try:
                                    parent = await parent.query_selector('..')
                                    if parent:
                                        text = await parent.inner_text()
                                        if "樊雨" in text:
                                            print(f"✓ 找到樊雨对应的单选按钮 {i+1}")
                                            await radio.click()
                                            print("✓ 成功点击单选按钮")
                                            await asyncio.sleep(1)
                                            return True
                                    else:
                                        break
                                except:
                                    break
                    except:
                        continue
                        
            except Exception as e:
                print(f"方法3失败: {e}")
            
            # 方法4: 尝试通过位置选择（如果是第3个）
            print("方法4: 尝试选择第3个语音选项...")
            try:
                # 查找可能是语音选项的元素组
                possible_voice_groups = [
                    'div[class*="voice"]',
                    'li',
                    '.voice-option',
                    '[role="option"]',
                    'div:has(input[type="radio"])'
                ]
                
                for selector in possible_voice_groups:
                    try:
                        elements = await self.page.query_selector_all(selector)
                        if len(elements) >= 3:
                            # 尝试点击第3个元素
                            third_element = elements[2]  # 索引从0开始，所以第3个是索引2
                            if await third_element.is_visible():
                                text = await third_element.inner_text()
                                print(f"第3个元素文本: {text[:100]}")
                                if "樊雨" in text or len(elements) == 4:  # 如果文本包含樊雨，或者总共4个选项
                                    await third_element.click()
                                    print("✓ 成功点击第3个语音选项")
                                    await asyncio.sleep(1)
                                    return True
                    except:
                        continue
                        
            except Exception as e:
                print(f"方法4失败: {e}")
            
            print(f"⚠ 所有方法都失败，未找到语音 '{voice_name}'，将使用默认语音")
            return False
            
        except Exception as e:
            print(f"❌ 选择语音失败: {str(e)}")
            return False
    
    async def analyze_voice_page_structure(self):
        """分析语音选择页面的结构"""
        print("\n=== 分析语音选择页面结构 ===")
        
        try:
            # 1. 查找所有可能的语音相关元素
            print("1. 查找所有可能包含语音信息的元素...")
            
            # 查找包含数字的元素（可能是语音编号）
            numbered_elements = await self.page.query_selector_all('*:has-text("999"), *:has-text("349"), *:has-text("348")')
            print(f"找到包含编号的元素: {len(numbered_elements)} 个")
            for i, elem in enumerate(numbered_elements):
                try:
                    text = await elem.inner_text()
                    tag_name = await elem.evaluate('el => el.tagName')
                    class_name = await elem.get_attribute('class') or 'N/A'
                    print(f"  编号元素 {i+1}: <{tag_name}> class='{class_name}' 文本: {text[:100]}")
                except:
                    pass
            
            # 2. 查找所有包含"樊雨"的元素
            print("\n2. 查找包含'樊雨'的所有元素...")
            fanyu_elements = await self.page.query_selector_all('*:has-text("樊雨")')
            print(f"找到包含'樊雨'的元素: {len(fanyu_elements)} 个")
            
            for i, elem in enumerate(fanyu_elements):
                try:
                    text = await elem.inner_text()
                    tag_name = await elem.evaluate('el => el.tagName')
                    class_name = await elem.get_attribute('class') or 'N/A'
                    is_clickable = await elem.evaluate('el => window.getComputedStyle(el).cursor === "pointer"')
                    print(f"  樊雨元素 {i+1}: <{tag_name}> class='{class_name}' 可点击: {is_clickable}")
                    print(f"    文本: {text[:150]}")
                    
                    # 查找父元素
                    parent = await elem.query_selector('..')
                    if parent:
                        parent_tag = await parent.evaluate('el => el.tagName')
                        parent_class = await parent.get_attribute('class') or 'N/A'
                        print(f"    父元素: <{parent_tag}> class='{parent_class}'")
                        
                except Exception as e:
                    print(f"  分析樊雨元素 {i+1} 失败: {e}")
            
            # 3. 查找所有单选按钮和相关的label
            print("\n3. 查找单选按钮和标签...")
            radio_elements = await self.page.query_selector_all('input[type="radio"], input[type="checkbox"]')
            print(f"找到单选/复选按钮: {len(radio_elements)} 个")
            
            for i, radio in enumerate(radio_elements):
                try:
                    input_type = await radio.get_attribute('type')
                    name = await radio.get_attribute('name') or 'N/A'
                    value = await radio.get_attribute('value') or 'N/A'
                    is_checked = await radio.is_checked()
                    
                    print(f"  按钮 {i+1}: type='{input_type}' name='{name}' value='{value}' checked={is_checked}")
                    
                    # 查找关联的label
                    label_id = await radio.get_attribute('id')
                    if label_id:
                        label = await self.page.query_selector(f'label[for="{label_id}"]')
                        if label:
                            label_text = await label.inner_text()
                            print(f"    关联标签: {label_text[:100]}")
                    
                    # 查找父容器的文本
                    parent = await radio.query_selector('..')
                    if parent:
                        parent_text = await parent.inner_text()
                        if "樊雨" in parent_text:
                            print(f"    ✓ 父容器包含樊雨: {parent_text[:100]}")
                            
                except Exception as e:
                    print(f"  分析按钮 {i+1} 失败: {e}")
            
            # 4. 保存页面截图用于调试
            await self.page.screenshot(path="voice_page_debug.png", full_page=True)
            print("\n4. 已保存页面截图: voice_page_debug.png")
            
        except Exception as e:
            print(f"页面结构分析失败: {str(e)}")
    
    async def try_click_fanyu_voice(self):
        """尝试点击樊雨语音的多种方法"""
        print("\n=== 尝试点击樊雨语音 ===")
        
        try:
            # 方法1: 直接通过ID查找单选按钮 (最精确的方法)
            print("方法1: 通过ID查找樊雨单选按钮...")
            try:
                radio_fanyu = await self.page.query_selector('#RadioUserSelectAnnouncerID999')
                if radio_fanyu:
                    is_visible = await radio_fanyu.is_visible()
                    is_enabled = await radio_fanyu.is_enabled()
                    print(f"找到樊雨单选按钮 ID=RadioUserSelectAnnouncerID999, 可见={is_visible}, 可用={is_enabled}")
                    
                    if is_visible and is_enabled:
                        await radio_fanyu.click()
                        print("✓ 成功点击樊雨单选按钮 (通过ID)")
                        await asyncio.sleep(1)
                        
                        # 验证是否选中
                        is_checked = await radio_fanyu.is_checked()
                        print(f"验证选中状态: {is_checked}")
                        return True
                    else:
                        print("樊雨单选按钮不可见或不可用")
                else:
                    print("未找到ID为RadioUserSelectAnnouncerID999的元素")
            except Exception as e:
                print(f"方法1失败: {e}")
            
            # 方法2: 通过value=999查找单选按钮
            print("方法2: 通过value=999查找单选按钮...")
            try:
                radio_999 = await self.page.query_selector('input[type="radio"][value="999"]')
                if radio_999:
                    is_visible = await radio_999.is_visible()
                    print(f"找到value=999的单选按钮, 可见={is_visible}")
                    
                    if is_visible:
                        await radio_999.click()
                        print("✓ 成功点击樊雨单选按钮 (通过value)")
                        await asyncio.sleep(1)
                        
                        is_checked = await radio_999.is_checked()
                        print(f"验证选中状态: {is_checked}")
                        return True
                else:
                    print("未找到value=999的单选按钮")
            except Exception as e:
                print(f"方法2失败: {e}")
            
            # 方法3: 通过name属性查找所有相关单选按钮
            print("方法3: 通过name属性查找单选按钮...")
            try:
                radio_buttons = await self.page.query_selector_all('input[name="RadioUserSelectAnnouncerID"]')
                print(f"找到 {len(radio_buttons)} 个语音单选按钮")
                
                for i, radio in enumerate(radio_buttons):
                    try:
                        value = await radio.get_attribute('value')
                        radio_id = await radio.get_attribute('id')
                        is_visible = await radio.is_visible()
                        
                        print(f"  单选按钮 {i+1}: value={value}, id={radio_id}, 可见={is_visible}")
                        
                        if value == "999" and is_visible:
                            await radio.click()
                            print("✓ 成功点击樊雨单选按钮 (通过name查找)")
                            await asyncio.sleep(1)
                            
                            is_checked = await radio.is_checked()
                            print(f"验证选中状态: {is_checked}")
                            return True
                            
                    except Exception as e:
                        print(f"  处理单选按钮 {i+1} 失败: {e}")
                        continue
                        
            except Exception as e:
                print(f"方法3失败: {e}")
            
            # 方法4: 点击包含樊雨的label元素
            print("方法4: 尝试点击樊雨的label标签...")
            try:
                label_fanyu = await self.page.query_selector('label[for="RadioUserSelectAnnouncerID999"]')
                if label_fanyu:
                    is_visible = await label_fanyu.is_visible()
                    print(f"找到樊雨label, 可见={is_visible}")
                    
                    if is_visible:
                        await label_fanyu.click()
                        print("✓ 成功点击樊雨label")
                        await asyncio.sleep(1)
                        
                        # 检查对应的单选按钮是否被选中
                        radio = await self.page.query_selector('#RadioUserSelectAnnouncerID999')
                        if radio:
                            is_checked = await radio.is_checked()
                            print(f"验证选中状态: {is_checked}")
                            return is_checked
                else:
                    print("未找到樊雨的label")
            except Exception as e:
                print(f"方法4失败: {e}")
            
            # 方法5: 强制使用JavaScript设置选中状态
            print("方法5: 使用JavaScript强制选中...")
            try:
                result = await self.page.evaluate("""
                    () => {
                        const radio = document.querySelector('#RadioUserSelectAnnouncerID999');
                        if (radio) {
                            radio.checked = true;
                            radio.click();
                            
                            // 触发change事件
                            const event = new Event('change', { bubbles: true });
                            radio.dispatchEvent(event);
                            
                            return radio.checked;
                        }
                        return false;
                    }
                """)
                
                if result:
                    print("✓ 成功通过JavaScript选中樊雨语音")
                    await asyncio.sleep(1)
                    return True
                else:
                    print("JavaScript方法也失败了")
                    
            except Exception as e:
                print(f"方法5失败: {e}")
            
            return False
            
        except Exception as e:
            print(f"尝试点击樊雨语音失败: {str(e)}")
            return False
    
    async def click_convert_button(self):
        """点击转换按钮"""
        print("正在查找并点击转换按钮...")
        
        # 可能的转换按钮选择器
        convert_selectors = [
            'button:has-text("转换")',
            'button:has-text("合成")',
            'button:has-text("生成")',
            'input[type="submit"]',
            'button[type="submit"]',
            '.convert-btn',
            '.submit-btn',
            '#convert',
            '#submit'
        ]
        
        for selector in convert_selectors:
            try:
                element = await self.page.query_selector(selector)
                if element:
                    is_visible = await element.is_visible()
                    is_enabled = await element.is_enabled()
                    
                    if is_visible and is_enabled:
                        print(f"✓ 找到转换按钮: {selector}")
                        await element.click()
                        print("✓ 已点击转换按钮")
                        return True
            except Exception as e:
                continue
        
        print("❌ 未找到可用的转换按钮")
        return False
    
    async def download_audio_file(self, text_content: str):
        """下载生成的音频文件"""
        print("等待3秒后开始下载...")
        await asyncio.sleep(3)  # 等待3秒再开始下载
        
        print("正在查找并点击下载按钮...")
        
        # 可能的下载按钮选择器
        download_selectors = [
            'button:has-text("下载文件到本地")',
            'button:has-text("下载")',
            'a:has-text("下载文件到本地")',
            'a:has-text("下载")',
            '.download-btn',
            '#download',
            'a[href*="download"]',
            'button[onclick*="download"]'
        ]
        
        for selector in download_selectors:
            try:
                elements = await self.page.query_selector_all(selector)
                print(f"查找下载按钮 {selector}: 找到 {len(elements)} 个元素")
                
                for i, element in enumerate(elements):
                    try:
                        is_visible = await element.is_visible()
                        is_enabled = await element.is_enabled()
                        
                        print(f"  下载按钮 {i+1}: 可见={is_visible}, 可用={is_enabled}")
                        
                        if is_visible and is_enabled:
                            # 获取按钮文本确认
                            button_text = await element.inner_text()
                            print(f"  按钮文本: '{button_text}'")
                            
                            print(f"✓ 找到可用的下载按钮: {selector} (第{i+1}个)")
                            
                            try:
                                # 设置下载处理
                                async with self.page.expect_download(timeout=30000) as download_info:
                                    await element.click()
                                    print("✓ 已点击下载按钮，等待下载开始...")
                                
                                download = await download_info.value
                                
                                # 确保下载目录存在
                                import os
                                downloads_dir = "/Users/maergaiyun/dev/project/ttsmaker-crawler/downloads"
                                os.makedirs(downloads_dir, exist_ok=True)
                                
                                # 生成安全的文件名（移除特殊字符）
                                import re
                                safe_filename = re.sub(r'[<>:"/\\|?*]', '_', text_content)
                                safe_filename = safe_filename.strip()
                                if not safe_filename:
                                    safe_filename = f"audio_{int(time.time())}"
                                
                                final_filename = f"{safe_filename}.mp3"
                                download_path = f"{downloads_dir}/{final_filename}"
                                
                                await download.save_as(download_path)
                                print(f"✓ 文件已下载并重命名为: {final_filename}")
                                print(f"  保存路径: {download_path}")
                                
                                return True
                                
                            except Exception as download_error:
                                print(f"下载过程中出错: {str(download_error)}")
                                # 如果下载超时，尝试直接保存
                                continue
                            
                    except Exception as e:
                        print(f"  下载按钮 {i+1} 点击失败: {str(e)}")
                        continue
                        
            except Exception as e:
                print(f"查找下载按钮 {selector} 失败: {str(e)}")
                continue
        
        print("❌ 未找到可用的下载按钮")
        return False
    
    async def process_csv_texts(self, csv_file_path: str):
        """批量处理 CSV 文件中的文本"""
        print(f"\n=== 开始批量处理 CSV 文件: {csv_file_path} ===")
        
        # 读取 CSV 文件
        texts = self.read_csv_file(csv_file_path)
        if not texts:
            print("❌ 没有找到要处理的文本")
            return
        
        results = []
        
        for i, text in enumerate(texts, 1):
            print(f"\n--- 处理第 {i}/{len(texts)} 条文本 ---")
            print(f"当前文本: {text}")
            
            try:
                # 1. 输入文本
                if not await self.input_text_to_page(text):
                    print(f"❌ 第 {i} 条文本输入失败")
                    results.append({"text": text, "status": "输入失败"})
                    continue
                
                # 2. 分析页面结构并选择语音（Fy-樊雨-经典男声）
                await self.analyze_voice_page_structure()
                
                # 尝试多种方法点击樊雨语音
                voice_selected = await self.try_click_fanyu_voice()
                if not voice_selected:
                    print("⚠ 樊雨语音选择失败，尝试原始方法...")
                    await self.select_voice("Fy-樊雨-经典男声")
                
                # 3. 点击转换按钮
                if not await self.click_convert_button():
                    print(f"❌ 第 {i} 条文本转换按钮点击失败")
                    results.append({"text": text, "status": "转换失败"})
                    continue
                
                # 4. 等待转换完成
                if await self.wait_for_conversion_complete():
                    print(f"✓ 第 {i} 条文本转换成功")
                    
                    # 5. 下载音频文件（传入文本内容用于重命名）
                    if await self.download_audio_file(text):
                        print(f"✓ 第 {i} 条文本音频文件下载成功")
                        results.append({"text": text, "status": "转换并下载成功"})
                    else:
                        print(f"⚠ 第 {i} 条文本转换成功但下载失败")
                        results.append({"text": text, "status": "转换成功但下载失败"})
                else:
                    print(f"❌ 第 {i} 条文本转换超时或失败")
                    results.append({"text": text, "status": "转换超时"})
                
                # 6. 等待3秒后处理下一条（避免请求过快）
                if i < len(texts):
                    print("下载完成，等待 3 秒后处理下一条...")
                    await asyncio.sleep(3)
                
            except Exception as e:
                print(f"❌ 处理第 {i} 条文本时出错: {str(e)}")
                results.append({"text": text, "status": f"出错: {str(e)}"})
        
        # 输出处理结果
        print(f"\n=== 批量处理完成 ===")
        print(f"总共处理: {len(texts)} 条文本")
        success_count = len([r for r in results if "成功" in r["status"]])
        download_success_count = len([r for r in results if r["status"] == "转换并下载成功"])
        print(f"完全成功（转换+下载）: {download_success_count} 条")
        print(f"转换成功: {success_count} 条")
        print(f"失败/错误: {len(texts) - success_count} 条")
        
        print("\n详细结果:")
        for i, result in enumerate(results, 1):
            print(f"{i}. {result['text']} -> {result['status']}")
    
    async def wait_for_user_login(self, check_interval: int = 3, max_wait_time: int = 300):
        """
        等待用户登录
        
        Args:
            check_interval (int): 检查间隔(秒)
            max_wait_time (int): 最大等待时间(秒)
        """
        print(f"\n=== 等待用户登录 (最大等待时间: {max_wait_time}秒) ===")
        print("请在浏览器中完成登录操作...")
        
        start_time = time.time()
        
        while time.time() - start_time < max_wait_time:
            # 检查登录状态
            if await self.check_login_status():
                print("✓ 检测到用户已成功登录！")
                return True
            
            print(f"等待登录中... (已等待 {int(time.time() - start_time)} 秒)")
            await asyncio.sleep(check_interval)
        
        print("⚠ 等待登录超时")
        return False
    
    async def get_page_content(self):
        """获取页面内容"""
        try:
            # 获取页面HTML
            content = await self.page.content()
            
            # 获取页面截图
            screenshot_path = "/Users/maergaiyun/dev/project/ttsmaker-crawler/page_screenshot.png"
            await self.page.screenshot(path=screenshot_path, full_page=True)
            print(f"页面截图已保存到: {screenshot_path}")
            
            return content
            
        except Exception as e:
            print(f"获取页面内容失败: {str(e)}")
            return None
    
    async def close(self):
        """关闭浏览器"""
        try:
            if self.page:
                await self.page.close()
            if self.browser:
                await self.browser.close()
            if hasattr(self, 'playwright'):
                await self.playwright.stop()
            print("浏览器已关闭")
        except Exception as e:
            print(f"关闭浏览器时出现错误: {str(e)}")
    
    async def run(self):
        """主运行方法"""
        print("TTSMaker 爬虫启动中...")
        print("正在尝试解决 conda 环境下的浏览器兼容性问题...")
        
        try:
            # 设置浏览器
            await self.setup_browser()
            
            # 打开网站
            if await self.open_website():
                # 分析页面结构
                await self.analyze_page_structure()
                
                # 等待用户登录
                login_success = await self.wait_for_user_login()
                
                if login_success:
                    print("\n=== 登录成功，可以进行后续操作 ===")
                    # 再次分析页面结构（登录后可能有变化）
                    await self.analyze_page_structure()
                    
                    # 开始处理 CSV 文件
                    csv_file_path = "/Users/maergaiyun/dev/project/ttsmaker-crawler/test.csv"
                    await self.process_csv_texts(csv_file_path)
                
                # 保持浏览器打开，等待进一步指令
                print("\n" + "="*60)
                print("🎉 CSV 文件处理完成！浏览器保持打开状态")
                print("您可以在浏览器中查看结果或进行其他操作...")
                print("按 Ctrl+C 退出程序")
                print("="*60)
                
                try:
                    while True:
                        await asyncio.sleep(1)
                except KeyboardInterrupt:
                    print("\n收到退出信号，正在安全关闭...")
            
        except Exception as e:
            print(f"\n❌ 运行出错: {str(e)}")
            print("\n🔧 解决方案:")
            print("1. 安装所有浏览器: playwright install")
            print("2. 或单独安装: playwright install firefox")
            print("3. 检查 conda 环境: conda list playwright")
            print("4. 重新安装: pip uninstall playwright && pip install playwright")
            print("5. 尝试系统 Python: /usr/bin/python3 -m pip install playwright")
            import traceback
            traceback.print_exc()
        finally:
            await self.close()


async def main():
    """主函数"""
    print("TTSMaker 爬虫启动...")
    
    # 创建爬虫实例
    crawler = TTSMakerCrawler(headless=False)  # 使用有界面模式
    
    # 运行爬虫
    await crawler.run()


if __name__ == "__main__":
    asyncio.run(main())
